package com.googlecode.lemyriapode.implementation;

import com.googlecode.lemyriapode.regle.Position;
import com.googlecode.lemyriapode.run.Run;
import com.googlecode.lemyriapode.type.AFPosition;

import com.googlecode.lemyriapode.type.Echiquier;
import static com.googlecode.lemyriapode.type.Echiquier.Case.*;

public class FPath extends AFPosition {

    public FPath() {
        super();
        position = new Position();
        f0(position);

    }

    /**
     * Implementation de AFonction du parcours de l'échiquier de a1 à h8
     * @author Gilles
     */
    public FPath(final Run analyse) {
        super();
        position = new Position();
//        this.analyse = analyse;

    }

    @Override
    public boolean continuer(int n, Object position) {
        this.pos = (Position) position;
        return CaseInexistente.eval();
    }

    @Override
    public void executer(int n, Object position) {

        System.out.println();
        _Case_C();
        _Piece_En_C();
        SiSinon(PieceAJouer, new IClosure() {

            public void exec() {
                new FDirection(null).f0(new Position(_c, echq.getDirection()));
            }
        }, RienAFaire);
        _Case_Suivante();

    }

    @Override
    public Object stopper(int n, Object e) {
        return null;
    }

    public class FDirection extends FPath {

        public FDirection(Run regle) {
            super(regle);
        }

        @Override
        public boolean continuer(int n, Object position) {
            this.pos = (Position) position;
            return FinDirection.eval();
        }

        @Override
        public void executer(int n, Object position) {
            _Case_C();
            _Piece_En_C();
            getDir();
            exploreDir = new IClosure() {

                public void exec() {
                    new FMDirection(null).f1(new Position(_c, dir));
                }
            };
            exploreDir1Case = new IClosure() {

                public void exec() {
                    new FMDirection1C(null).f1(new Position(_c, dir));
                }
            };
            if (DirectionAutorise.eval()) {
                SiSinon(DeplacementNCase, exploreDir, exploreDir1Case);
            }
            getNext_dir();
        }

        @Override
        public Object stopper(int n, Object e) {
            return null;
        }
    }

    /**
     * Iteration sur toutes les directions
     * T,F,D,R,P : 8 directions
     * C : 8 directions
     * @author Gilles
     */
    public class FMDirection extends FPath {

        public FMDirection(Run regle) {
            super(regle);
        }

        @Override
        public boolean continuer(int n, Object position) {

            Echiquier b = ((Position) position).getEchiquier();
            I = b.getCase().Ci() + n * b.getDirection().u;
            J = b.getCase().Rj() + n * b.getDirection().v;
            return !Echiquier.isOut(I, J);
        }

        @Override
        public void executer(int n, Object position) {
            System.out.print(getCase(I, J) + ",");
        }

        @Override
        public Object stopper(int n, Object position) {
            System.out.print("/");
            return null;
        }
    }

    /**
     * idem FMDirection1C en n'explorant qu'une case du voisinage de la piece (roi)
     * @author Gilles
     */
    public class FMDirection1C extends FPath {

        public FMDirection1C(Run regle) {
            super(regle);
        }

        @Override
        public boolean continuer(int n, Object position) {

            Echiquier b = ((Position) position).getEchiquier();
            I = b.getCase().Ci() + n * b.getDirection().u;
            J = b.getCase().Rj() + n * b.getDirection().v;
            return !Echiquier.isOut(I, J) && voisinage(n);
        }

        @Override
        public void executer(int n, Object e) {
            //  s.add(_case);
            System.out.print(getCase(I, J) + ",");
        }

        @Override
        public Object stopper(int n, Object e) {
            System.out.print("/");
            return null;
        }

        private boolean voisinage(int n) {
            return (n < 2);
        }
    }
}
